import React, { useState, useEffect } from "react";
import Recorder from "js-audio-recorder";
import { Button, Space, Input } from "antd";
import FlowText from "../../components/FlowText.tsx";
import {
  DeleteOutlined,
  FileTextOutlined,
  EditOutlined,
} from "@ant-design/icons";
import styles from "./voice.module.less";
import Header from "../../assets/voice/header.png";
import Sound from "../../assets/voice/sound.png";
import SoundActive from "../../assets/voice/soundActive.png";
import Pause from "../../assets/voice/pause.png";
import Checked from "../../assets/voice/checked.png";
import UnCheck from "../../assets/voice/uncheck.png";
import Question from "../../assets/voice/question.png";
import Consultation from "../../assets/voice/consultation.png";
import Meilian from "../../assets/voice/meilian.png";
import Admin from "../../assets/voice/admin.png";
import From from "../../assets/voice/from.png";
import Play from "../../assets/voice/play.png";
import Rebuild from "../../assets/voice/rebuild.png";
import { chat, speak, get_token } from "../../api/voice.ts";

const { TextArea } = Input;

const App: React.FC = () => {
  // 变量
  const [radio, setRadio] = useState(false);
  const [soundRecord, setSoundRecord] = useState(false);
  const [soundGet, setSoundGet] = useState(false);
  const [audioPlay1, setAudioPlay1] = useState(null);
  const [audioPlay2, setAudioPlay2] = useState(null);
  const [generate, setGenerate] = useState(true);
  const [status, setStatus] = useState("");
  const [inputValue, setInputValue] = useState("");
  const [radioResult, setRadioResult] = useState("");
  const [record, setRecord] = useState([]);
  //初始化录音实例
  const [recorder, setRecorder] = useState(
    new Recorder({
      sampleBits: 16, // 采样位数，，默认是16
      sampleRate: 16000, //音频采样率，默认是16000Hz，
      numChannels: 1, // 声道，支持 1 或 2， 默认是1
      compiling: true, // 是否边录边转换，默认是false
    })
  );
  //获取ali的token
  const [token, setToken] = useState("dfe2c3c2312d455caa60ffdec4a45d45");
  const [appkey, setAppkey] = useState("TUbE2MecE23ooOG7");
  const [ws, setWs] = useState({
    websocket: null,
    timer_websocket: null,
    websocket_task_id: "",
    websocket_audio2txt_time: 0,
    websocket_audio2txt_result_msg: "",
    websocket_audio2txt_result_msg_temp: null,
    websocket_audio2txt_complete_b: false,
    websocket_audio2txt_complete_time_end: 100,
  });
  const [webTimer, setWebTimer] = useState(null);

  // 方法
  const getToken = () => {
    get_token().then((res) => {
      if (res.code == 200) {
        setToken(res.data);
      }
    });
  };
  const statusChange = (val) => {
    // 切换任务
    setStatus(val);
    loadAudio(
      {
        content:
          val == "question"
            ? "请描述一下您的问题。"
            : "请描述一下您现在的主要不适症状，并告诉我您的性别和年龄。",
      },
      "default"
    );
    setGenerate(true);
    clearRecord();
  };
  const clearRecord = () => {
    // 清空聊天记录
    if (record.length > 0 && record[record.length - 1].timer) {
      clearInterval(record[record.length - 1].timer);
    }
    setRecord([]);
  };
  const soundChange = (val, index) => {
    // 播放语音
    console.log("播放语音");
    console.log(audioPlayer);
    if (audioPlayer.playingMessage) {
      // this.audioPlayer.innerAudioContext.stop();
      // 如果点击的消息正在播放，就认为是停止播放操作
      if (audioPlayer.playingMessage === record[index]) {
        if (!audioPlayer.loading) {
          audioPlayer.innerAudioContext.currentTime = 0;
          audioPlayer.innerAudioContext.play();
        } else {
          audioPlayer.innerAudioContext.pause();
        }
        setAudioPlayer({
          ...audioPlayer,
          loading: !audioPlayer.loading
        })
        return;
      } else {
        audioPlayer.innerAudioContext.pause();
      }
    }
    audioPlayer.innerAudioContext.currentTime = 0;
    audioPlayer.innerAudioContext.src = record[index].src;
    audioPlayer.innerAudioContext.play();
    setAudioPlayer({
      ...audioPlayer,
      loading: true,
      playingMessage: record[index]
    })
    // const arr = record;
    // if (val) {
    //   arr[index].playing.play()
    //   console.log('列表语音播放', arr[index].playing, audioPlay1, audioPlay2, record)
    // } else {
    //   arr[index].playing.pause()
    //   arr[index].playing.currentTime = 0
    //   console.log('列表语音停止', arr[index].playing, audioPlay1, audioPlay2, record)
    // }
    // arr[index].sound = val;
    // setRecord([...arr])
  };

  const [audioPlayer, setAudioPlayer] = useState({
    innerAudioContext: null,
    loading: false,
    playingMessage: null,
  });

  useEffect(() => {
    if (audioPlayer.innerAudioContext) {
      audioPlayer.innerAudioContext.addEventListener(
        "ended",
        audioPlayerOver,
        false
      );
    }
  }, [audioPlayer.innerAudioContext]);

  // 初始化audio标签
  const initialAudioPlayer = () => {
    setAudioPlayer({
      ...audioPlayer,
      innerAudioContext: document.createElement("audio"),
    });
  };

  // 播放结束
  const audioPlayerOver = () => {
    console.log("播放结束");
    setAudioPlayer({
      ...audioPlayer,
      playingMessage: null,
      loading: false,
    });
  };

  // 播放语音
  const playing = (val) => {
    // console.log('播放默认', audioPlay1, audioPlay2)
    // 默认任务问题播放
    // if (val) {
    //   setSoundGet(true)
    //   console.log('语音播放')
    //   status == 'question' ? audioPlay1.play() : audioPlay2.play()
    // } else {
    //   setSoundGet(false)
    //   if (status == 'question') {
    //     audioPlay1.pause()
    //     audioPlay1.currentTime = 0
    //   } else {
    //     audioPlay2.pause()
    //     audioPlay2.currentTime = 0
    //   }
    //   console.log('语音停止')
    // }
  };
  const loadAudio = (item, type) => {
    const params = {
      text: item.content,
    };
    if (type == "default") {
      if (!audioPlay1 || !audioPlay2) {
        speak(params).then((res) => {
          console.log("录音文件", res);
          const blob = new Blob([res], { type: "audio/wav" });
          const localUrl = (window.URL || webkitURL).createObjectURL(blob);
          let mp3 = new Audio(blob);
          mp3.src = localUrl;
          if (status == "question") {
            setAudioPlay2(mp3);
          } else {
            setAudioPlay1(mp3);
          }
        });
      }
    } else {
      // if (!item.playing) {
        speak(params).then((res) => {
          const blob = new Blob([res], { type: "audio/wav" });
          const localUrl = (window.URL || webkitURL).createObjectURL(blob);
          // let mp3 = new Audio(blob);
          // mp3.src = localUrl;
          // mp3.addEventListener("canplay", function () {
          //   let duration = mp3.duration;
          //   console.log("录音的时长", duration, blob, mp3);
          // });
          // mp3.addEventListener("ended", function () {
          //   console.log("音频播放结束");
          // });
          // item.playing = mp3;
          item.src = localUrl;
          // setRecord([...record, statu, item]);
          setRecord([...record, item]);
        });
      // }
    }
  };
  const stopAndstartGenerate = (val, bool) => {
    const arr = record;
    if (!bool) {
      setGenerate(false);
      clearInterval(val.timer);
      val.timer = null;
      console.log("停止生成");
    } else {
      console.log("重新生成");
      setGenerate(true);
      val.text = [];
      val.str = "";
      val.start = 0;
      val.end = 1;
      arr.pop();
      val.timer = setInterval(() => {
        val.text = val.content.split("");
        const scr = val.text.slice(val.start, val.end);
        val.str += scr;
        val.start += 1;
        val.end += 1;
        if (val.end > val.text.length) {
          clearInterval(val.timer);
          val.timer = null;
          setGenerate(false);
        }
        setRecord([...arr, val]);
      }, 100);
    }
  };
  const generateRecord = () => {
    // 病历生成
    textFlow({}, "his");
  };
  const textFlow = (ask, type) => {
    let askList = [];
    let answerList = [];
    let historyList = [];
    record.forEach((item) => {
      if (item.type == "question") {
        askList.push(item);
      } else if (item.type == "answer") {
        answerList.push(item);
      }
    });
    for (let i = 0; i < askList.length; i++) {
      historyList.push({
        ask: askList[i].content,
        answer: answerList[i].content,
      });
    }
    const params = {
      type: type,
      query: type == "chat" ? ask.content : "",
      history: historyList,
    };
    chat(params).then((res) => {
      if (res && res.code == 200) {
        const state = {
          type: "answer",
          content: res.data,
        };
        state.sound = false;
        state.playing = null;
        state.text = [];
        state.timer = null;
        state.start = 0;
        state.end = 1;
        state.str = res.data;
        // state.timer = setInterval(() => {
        //     state.text = state.content.split('');
        //     const scr = state.text.slice(state.start, state.end);
        //     state.str += scr;
        //     state.start += 1;
        //     state.end += 1;
        //     if (state.end > state.text.length) {
        //         clearInterval(state.timer)
        //         state.timer = null;
        //         setGenerate(false)
        //     }
        //     if (type == 'chat') {
        //       setRecord([...record, ask, state])
        //     } else {
        //       setRecord([...record, state])
        //     }
        // }, 100);
        loadAudio(state, "recordList", ask);
        // 不用流式可以的
        setGenerate(false);
        if (type == "chat") {
          setRecord([...record, ask, state]);
        } else {
          setRecord([...record, state]);
        }
      } else {
        record.pop();
        setRecord([...record]);
      }
    });
  };
  // 录音部分
  const startRecord = () => {
    setSoundRecord(true);
    recorder.start().then(() => {
      setWs({ ...ws, websocket_audio2txt_result_msg: "" });
      initWebSocket();
    });
  };
  const stopRecord = () => {
    console.log("结果", radioResult);
    setInputValue(radioResult);
    setSoundRecord(false);
    recorder.stop();
    clearInterval(webTimer);
    setWebTimer(null);
  };
  const initWebSocket = () => {
    setWs({ ...ws, websocket_audio2txt_complete_b: false });
    setWs({ ...ws, websocket_audio2txt_time: 0 });
    if (ws.websocket !== null) {
      ws.websocket.close();
      ws.websocket = null;
    }
    const wsuri = `wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1?token=${token}`;
    //连接wss服务端
    ws.websocket = new WebSocket(wsuri);
    //指定回调函数
    ws.websocket.onopen = websocketOnOpen;
    ws.websocket.onmessage = websocketOnMessage;
  };
  const websocketOnOpen = () => {
    setWs({ ...ws, websocket_task_id: getRandomStrNum() });
    const message_id = getRandomStrNum();
    const actions = {
      header: {
        namespace: "SpeechTranscriber", //固定值
        name: "StartTranscription", //发送请求的名称，固定值
        appkey: appkey, //appkey
        message_id: message_id, //消息id
        task_id: ws.websocket_task_id, //任务id
      },
      payload: {
        format: "PCM", //音频编码格式，默认是PCM（无压缩的PCM文件或WAV文件），16bit采样位数的单声道。
        sample_rate: 16000, //需要与录音采样率一致、默认是16000，单位是Hz。
        enable_intermediate_result: true, //是否返回中间识别结果，默认是false。
        enable_punctuation_prediction: true, //是否在后处理中添加标点，默认是false。
        enable_inverse_text_normalization: true, //是否在后处理中执行数字转写，默认是false。
        max_sentence_silence: 500, //	语音断句检测阈值，静音时长超过该阈值会被认为断句，参数范围200ms～2000ms，默认值800ms。
      },
    };
    //发送请求
    websocketSend(JSON.stringify(actions));
  };
  const websocketSend = (data) => {
    if (ws.websocket.readyState === 1) {
      ws.websocket.send(data);
    } else {
      console.log("websock未连接-------", ws.websocket);
    }
  };
  const websocketOnMessage = (e) => {
    //接受ali 语音返回的数据
    const ret = JSON.parse(e.data);
    console.log("输入框", ret, inputValue);
    //判断返回的数据类型
    if (ret.header.name === "TranscriptionResultChanged") {
      //数据在收集中 一句话的中间结果
      //实时获取语音转文本的结果
      endText(ret.payload.result);
      console.log("数据在收集中", ret);
    } else if (ret.header.name === "SentenceBegin") {
      //一句话开始后，就可以启动录音了
      console.log("检测到了一句话的开始");
    } else if (ret.header.name === "TranscriptionStarted") {
      console.log("服务端已经准备好了进行识别，客户端可以发送音频数据了");
      //获取音频信息，定时获取并发送
      const interval = setInterval(() => {
        getPCMAndSend();
      }, 2000);
      setWebTimer(interval);
      console.log("定时器", webTimer);
    } else if (ret.header.name === "SentenceEnd") {
      endText(ret.payload.result);
      console.log("数据接收结束", ret);
    } else if (ret.header.name === "TranscriptionCompleted") {
      console.log("服务端已停止了语音转写", ret);
    }
  };
  const getPCMAndSend = () => {
    //获取音频信息
    // const NextData = recorder.getNextData();
    const NextData = recorder.getPCMBlob();
    const blob = new Blob([NextData]);
    const blob_size = blob.size;
    // console.log("获取音频信息，并发送,blob_size:"+blob_size , blob);

    //ali最大支持3200字节的音频
    const max_blob_size = 3200; //支持1600 或3200
    let my_num = blob_size / max_blob_size;
    my_num = my_num + 1;

    //切分音频发送
    for (let i = 0; i < my_num; i++) {
      let end_index_blob = max_blob_size * (i + 1);
      //判断结束时候的分界
      if (end_index_blob > blob_size) {
        end_index_blob = blob_size;
      }
      //切分音频
      const blob2 = blob.slice(i * max_blob_size, end_index_blob);
      //生成新的blob
      const newbolb = new Blob([blob2], { type: "audio/pcm" });
      //发送
      websocketSend(newbolb);
    }
  };
  const getRandomStrNum = () => {
    let s = [];
    let hexDigits = "0123456789abcdef";
    for (let i = 0; i < 32; i++) {
      s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
    s[8] = s[13] = s[18] = s[23];

    const uuid = s.join("");
    return uuid;
  };
  const endText = (text) => {
    ws.websocket_audio2txt_result_msg += text;
    setRadioResult(ws.websocket_audio2txt_result_msg);
    console.log(
      "websocket_audio2txt_result_msg:",
      ws.websocket_audio2txt_result_msg
    );
  };
  const sendMessage = () => {
    const obj = {
      type: "question",
      content: inputValue,
    };
    setRecord([...record, obj]);
    setInputValue("");
    textFlow(obj, "chat");
  };

  useEffect(() => {
    initWebSocket();
    getToken();
    initialAudioPlayer();
  }, []);

  // 页面组件
  const LeftMession: React.FC = () => {
    return (
      <>
        <div className={styles.content_box}>
          <p className={styles.try_input}>您可以尝试输入:</p>
          <p className={styles.example}>
            <EditOutlined />{" "}
            &nbsp;&nbsp;我最近总是打嗝，胃胀气，反流口水变多，偶尔有干呕和嘴苦
            ，持续一周多了，请问该吃点什么药缓解？
          </p>
          <p className={styles.example}>
            <EditOutlined />{" "}
            &nbsp;&nbsp;我是中央型颈椎病，现在颈痛，脖子僵硬，肩膀也酸痛，现在正在保守治疗，也做过牵引，已经有一年了，现在严重吗要不要手术？
          </p>
        </div>
        <div className={`${styles.content_box} ${styles.answer_box}`}>
          <img src={Meilian} className={styles.avatar} alt="" />
          <p>请描述一下您的问题。</p>
          <div className={styles.from}>
            {!soundGet ? "" : <span></span>}
            {!soundGet ? (
              <img src={Play} onClick={() => playing(true)} alt="" />
            ) : (
              <img src={Pause} onClick={() => playing(false)} />
            )}
            <img src={From} alt="" />
          </div>
        </div>
      </>
    );
  };
  const RightMession: React.FC = () => {
    return (
      <>
        <div className={styles.content_box}>
          <p className={styles.try_input}>您可以尝试输入:</p>
          <p className={styles.example}>
            <EditOutlined />{" "}
            &nbsp;&nbsp;头痛，恶心，反酸水，呕吐，中午吃了昨天的一点剩饭，一碗面条。下午没吃其他东西，（女，32）
          </p>
          <p className={styles.example}>
            <EditOutlined />{" "}
            &nbsp;&nbsp;我最近发现精索静脉曲张对身体会有什么影响？我应该注意些什么吗？我是一个30岁的男性
          </p>
        </div>
        <div className={`${styles.content_box} ${styles.answer_box}`}>
          <img src={Meilian} className={styles.avatar} alt="" />
          <p>请描述一下您现在的主要不适症状，并告诉我您的性别和年龄。</p>
          <div className={styles.from}>
            {!soundGet ? "" : <span></span>}
            {!soundGet ? (
              <img src={Play} onClick={() => playing(true)} alt="" />
            ) : (
              <img src={Pause} onClick={() => playing(false)} />
            )}
            <img src={From} alt="" />
          </div>
        </div>
      </>
    );
  };
  const RecordList: React.FC = () => {
    return record.map((item, index) => {
      return (
        <>
          {item.type == "question" ? (
            <div className={styles.question}>
              <img src={Admin} className={styles.avatar} alt="" />
              <p className={styles.answer}>{item.content}</p>
            </div>
          ) : (
            <div className={`${styles.content_box} ${styles.answer_box}`}>
              <img src={Meilian} className={styles.avatar} alt="" />
              {/* <p className={styles.answer}>{item.str}</p> */}
              <FlowText text={item.str}></FlowText>
              <div className={styles.from}>
                {!item.timer ? (
                  <>
                    {!item.sound ? "" : <span></span>}
                    {!item.sound ? (
                      <img
                        src={Play}
                        onClick={() => soundChange(true, index)}
                        alt=""
                      />
                    ) : (
                      <img
                        src={Pause}
                        onClick={() => soundChange(false, index)}
                      />
                    )}
                  </>
                ) : (
                  ""
                )}
                <img src={From} alt="" />
              </div>
              {index + 1 == record.length ? (
                generate ? (
                  <div
                    className={styles.generate}
                    onClick={() => stopAndstartGenerate(item, false)}
                  >
                    停止生成
                  </div>
                ) : (
                  <div
                    className={styles.generate}
                    onClick={() => stopAndstartGenerate(item, true)}
                  >
                    <img src={Rebuild} alt="" />
                    重新生成
                  </div>
                )
              ) : (
                ""
              )}
            </div>
          )}
        </>
      );
    });
  };

  return (
    <div className={styles.page}>
      <div className={styles.body}>
        {/* 聊天记录 */}
        <div className={styles.chat_content}>
          <img src={Meilian} className={styles.avatar} alt="" />
          <img src={Header} alt="" />
          <div className={styles.content_box}>
            <img src={Meilian} className={styles.avatar} alt="" />
            <p className={styles.title}>请选择您的专题任务</p>
            <div className={styles.messions}>
              <div
                className={`${styles.mession_left} ${
                  status == "question" ? styles.mession_active : ""
                }`}
                onClick={() => statusChange("question")}
              >
                <img src={Question} alt="" />
                <div className={styles.mession_info}>
                  <p>
                    <span>常见病医学知识问答</span>
                    <img
                      src={status == "question" ? Checked : UnCheck}
                      alt=""
                    />
                  </p>
                  <p>解答常见病医学内容相关知识性问题。</p>
                </div>
              </div>
              <div
                className={`${styles.mession_right} ${
                  status == "consultation" ? styles.mession_active : ""
                }`}
                onClick={() => statusChange("consultation")}
              >
                <img src={Consultation} alt="" />
                <div className={styles.mession_info}>
                  <p>
                    <span>预问诊</span>
                    <img
                      src={status == "consultation" ? Checked : UnCheck}
                      alt=""
                    />
                  </p>
                  <p>
                    在医生问诊前，通过对话采集患者重要健康信息，并生成相应问诊病历。
                  </p>
                </div>
              </div>
            </div>
          </div>
          {status == "question" ? (
            <LeftMession />
          ) : status == "consultation" ? (
            <RightMession />
          ) : (
            ""
          )}
          <RecordList />
        </div>
        {/* 聊天输入框 */}
        <div className={styles.chat_window}>
          <div className={styles.chat_button}>
            <div className={styles.button_left}>
              <Space>
                <Button
                  className={status == "question" ? styles.active : ""}
                  onClick={() => statusChange("question")}
                >
                  常见病医学知识问答
                </Button>
                <Button
                  className={status == "consultation" ? styles.active : ""}
                  onClick={() => statusChange("consultation")}
                >
                  预问诊
                </Button>
              </Space>
            </div>
            <div className={styles.button_right}>
              <Space>
                {status == "consultation" ? (
                  <Button
                    icon={<FileTextOutlined />}
                    shape="round"
                    disabled={record.length > 0 && generate}
                    onClick={generateRecord}
                  >
                    生成病历记录
                  </Button>
                ) : (
                  ""
                )}
                <Button
                  icon={<DeleteOutlined />}
                  shape="round"
                  onClick={clearRecord}
                >
                  清空聊天记录
                </Button>
              </Space>
            </div>
          </div>
          <div className={styles.chat_input}>
            <TextArea
              value={inputValue}
              onChange={(e) => setInputValue(e.target.value)}
              placeholder="在此输入你的问题"
              autoSize={{ minRows: 2.5, maxRows: 2.5 }}
              bordered={false}
            />
            <div className={styles.chat_input_bottom}>
              {!soundRecord ? "" : <span></span>}
              {!soundRecord ? (
                <img
                  src={radio ? SoundActive : Sound}
                  onMouseEnter={() => setRadio(true)}
                  onMouseLeave={() => setRadio(false)}
                  onClick={startRecord}
                  alt=""
                />
              ) : (
                <img src={Pause} onClick={stopRecord} />
              )}
              <Button
                disabled={
                  status == "" ||
                  inputValue == "" ||
                  (record.length > 0 && generate)
                    ? true
                    : false
                }
                onClick={sendMessage}
                type="primary"
              >
                发送
              </Button>
            </div>
          </div>
        </div>
        <div className={styles.footer}>
          服务生成的所有内容均由人工智能模型生成，其生成内容的准确性和完整性无法保证，不代表我们的态度或观点
        </div>
      </div>
    </div>
  );
};

export default App;
